﻿using System;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;

namespace Pg.BioMedics.SDR.Web.Security
{
    /// <summary>
    /// static utility class providing support for windows domain authentication routines
    /// </summary>
    internal static class WindowsIdentityHelper
    {
        #region Constants

        public const int LOGON32_LOGON_INTERACTIVE = 2;
        public const int LOGON32_PROVIDER_DEFAULT = 0;

        #endregion

        #region External WINAPI methods

        [DllImport("advapi32.dll")]
        internal static extern int LogonUserA(String lpszUserName,
                                              String lpszDomain,
                                              String lpszPassword,
                                              int dwLogonType,
                                              int dwLogonProvider,
                                              ref IntPtr phToken);
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern int DuplicateToken(IntPtr hToken,
                                                  int impersonationLevel,
                                                  ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        internal static extern bool CloseHandle(IntPtr handle);

        #endregion

        #region Methods

        internal static string GetDomainName(string identityName)
        {
            if (!identityName.Contains('\\') && !identityName.Contains('@'))
                return String.Empty;
            else if (identityName.Contains('\\'))
                return identityName.Split('\\').FirstOrDefault();
            else
                return identityName.Split('@').LastOrDefault();
        }

        internal static string GetUserName(string identityName)
        {
            if (!identityName.Contains('\\') && !identityName.Contains('@'))
                return identityName;
            else if (identityName.Contains('\\'))
                return identityName.Split('\\').LastOrDefault();
            else
                return identityName.Split('@').FirstOrDefault();
        }

        internal static bool ValidateUser(String userName, String domain, String password)
        {
            IntPtr token = IntPtr.Zero;
            if (RevertToSelf())
            {
                if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                               LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                    return true;
                else
                    return false;
            }
            else
                return false;

            if (token != IntPtr.Zero)
                CloseHandle(token);
        }

        internal static WindowsImpersonationContext ImpersonateValidUser(String userName, String domain, String password)
        {
            WindowsIdentity tempWindowsIdentity;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            if (RevertToSelf())
            {
                if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                               LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                {
                    if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                    {
                        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                        WindowsImpersonationContext impersonationContext = tempWindowsIdentity.Impersonate();
                        if (impersonationContext != null)
                        {
                            CloseHandle(token);
                            CloseHandle(tokenDuplicate);
                            return impersonationContext;
                        }
                    }
                }
            }
            if (token != IntPtr.Zero)
                CloseHandle(token);
            if (tokenDuplicate != IntPtr.Zero)
                CloseHandle(tokenDuplicate);

            return null;
        }

        internal static void UndoImpersonation(WindowsImpersonationContext impersonationContext)
        {
            impersonationContext.Undo();
        }

        #endregion
    }
}
